package edu.ucla.cs.rpc.multicast.sequencer.fixed;

import java.io.IOException;
import java.net.SocketAddress;

import edu.ucla.cs.rpc.multicast.handlers.MessageHandler;
import edu.ucla.cs.rpc.multicast.network.MessageReceiver;
import edu.ucla.cs.rpc.multicast.network.MulticastMessageSender;
import edu.ucla.cs.rpc.multicast.network.message.Message;
import edu.ucla.cs.rpc.multicast.sequencer.Sequencer;

/**
 * A Fixed Sequencer is a process that acts as an intermediary between a Sender
 * and a Destination. It imposes a total order on the messages transmitted
 * between them.
 * 
 * @author Chase Covello Philip Russell
 * @see Total Order Broadcast and Multicast Algorithms: Taxonomy and Survery,
 *      Defago et al
 * @see Section 4.1, pages 12 - 13
 * 
 */
public class FixedSequencer implements Sequencer {

	private final MessageReceiver sequencer;

	private final MulticastMessageSender sender;

	private long seqNum = 1;

	/**
	 * Primary constructor.
	 * 
	 * @param multicastManager
	 *            The sending agent that will transmit RPCMessages accross the
	 *            channel to Destinations.
	 * @throws IOException
	 *             Thrown if the sending agent cannot be properly instantiated,
	 *             most likely due to an invalid Internet address & port
	 *             combination.
	 */
	public FixedSequencer(SocketAddress multicastManager) throws IOException {
		sequencer = new MessageReceiver(new FixedSequencerMessageHandler());
		sender = new MulticastMessageSender(multicastManager);
	}

	/**
	 * @return The Socket Address of this object, a communications portal.
	 */
	public SocketAddress getSocketAddress() {
		return sequencer.getSocketAddress();
	}

	/**
	 * Shuts down any threads created by this sequencer. This method <b>must</b>
	 * be called before disposing of all references to this object; otherwise,
	 * its thread will continue to run until the application is forcibly
	 * terminated.
	 */
	public void shutdown() {
		sequencer.shutdown();
		sender.shutdown();
	}

	private class FixedSequencerMessageHandler implements MessageHandler {

		public void receive(Message message) {
			try {
				message.setSeqNum(seqNum++);
				sender.send(message);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
